<script setup lang="ts">
import {Close} from '@element-plus/icons-vue'
import {ref, reactive, onMounted} from 'vue'
import {BubbleList, FilesCard, Thinking, Typewriter} from "vue-element-plus-x";
import dayjs from "dayjs";
//@ts-ignore
import type { BubbleListProps } from "vue-element-plus-x/types/components/BubbleList/types";
import SystemPanel from './system/index.vue'
import {ToolsProtocol} from "@/views/ai/miuma/chat/data";
import {ChatType,BluePrintApi} from '@/views/ai/agent/x6/api/blue-print-api'
import {ChatInputDTO} from "@/views/ai/miuma/chat/types";
import {messageBus} from './hook'
import {listType} from "@/views/ai/agent/x6/content-renderer";

const emits = defineEmits<{
  (e:'close'):void,
  (e:'mcp',v:{f:string,input:ChatType}):void
}>()
const bubbleItems = ref<BubbleListProps<ChatType>['list']>([])
const getNow=(now:Date)=>{
  return  dayjs(now).format('YYYY年MM月DD HH:mm:ss')
}
const hisId=ref<string>()
const chatting=ref(false)
const context = ref<BubbleListProps<ChatType>['list']>([])

//聊天窗口添加MCP组件
function addSystemMcp(m: any, input: ChatInputDTO) {
  bubbleItems.value.push({
    role: 'system',
    component: m.name,
    props: {input},
    maxWidth: '100%',
  })
  //todo 后续按照MCP类型唤起不同的组件
  if (['checkDocContentByRule','writingDoc'].includes(m.name)){
    //总线通知
    const e:ToolsProtocol={
      tools:true,
      component:'DocEditor',
      active:'DocEditorLoadFile',
      subData:{...input}
    }
    messageBus.emit('useTools',e)
  }
}

const handleMcp=(d, input: ChatInputDTO)=> {
  console.log(d,input)
  try {
    const mcpRes = d?.data?.responses
    if (mcpRes) {
      for (const m of mcpRes) {
        addSystemMcp(m, input);
      }
    }
  } catch (e) {
    console.error(e)
  }
}

const query=async (input:ChatInputDTO)=>{
  console.log('sendMsgToAi')
  const ums:ChatType={
    role:'user',
    placement:'start',
    content:input.query,
    loading:false,
    atTime:new Date(),
    files:input.files
  }
  bubbleItems.value.push(ums)
  if (!hisId.value){
    hisId.value=await BluePrintApi.createHis('default',ums as listType)
  }
  const sseMsg=reactive<ChatType>({
    role:'ai',
    placement:'end',
    chunk:[],
    loading:true,
    thinking:true,
  })
  bubbleItems.value.push(sseMsg)
  const slicedArray=(arr:any[],n:number)=>{
    if (arr.length>n){
      return arr.slice(arr.length-n,arr.length)
    }else {
      return arr
    }
  }
  let aires=''
  let think=''

  await BluePrintApi.executeByCode('default',{text:input.query,files:input.files,context:slicedArray(context.value,5)},
    (ev)=>{
    //防止一直重复调用
      try {
        const d=JSON.parse(ev.data)
        //{"node":"LLM_EXEC","content":null,"data":null,"status":"start"}
        if (d.node==='LLM_EXEC'&&d.status==='start'){
          sseMsg.loading=false
        }
        if (d.node==='LLM_EXEC'&&d.status!='completed'){
          if (d.content&&d.content?.startsWith('<think>')){
            think+=d.content.replaceAll("<think>","").replaceAll("</think>","")
          }else {
            aires+=d.content||''
          }
        }
        sseMsg.content=aires
        sseMsg.think=think
        if (d.node==='MCP_RES'){
          handleMcp(d, input);
        }
        if (d.node==='LLM_EXEC'&&d.status==='completed'){
          sseMsg.thinking=false
        }
      }catch (e){
        console.error(e)
      }
    },
    ()=>{
      sseMsg.atTime=new Date()
      //保存聊天历史
      if (hisId.value){
        console.log("保存聊天记录!")
        BluePrintApi.pushChat2His(hisId.value,[ums,sseMsg] as listType[])
      }
      //每次完成聊天，push 到聊天上下文
      context.value.push(ums)
      context.value.push(sseMsg)
      chatting.value=false
    },
    undefined,
    (e)=>{
      console.error('sendMsgToAi',e)
      sseMsg.content='出错了，请重试!'
      sseMsg.loading=false
      sseMsg.atTime=new Date()
      throw e
    }
  )
}
const onPushMcp=(e)=>{
  console.log('onPushMcp',e)
}
defineExpose({
  query
})
onMounted(()=>{
  messageBus.on('pushMcp',onPushMcp)
})
onBeforeUnmount(()=>{
  messageBus.off('pushMcp',onPushMcp)
})
</script>

<template>
  <!-- @ts-ignore -->
  <div class="chat-panel">
    <div class="chat-panel-close">
      <el-button style="z-index: 1000" round :icon="Close" @click="emits('close')">
        关闭
      </el-button>
    </div>
    <BubbleList class="body-inner" :list="bubbleItems" max-height="100%">
      <!-- 自定义头像 -->
      <template #avatar="{ item }">
        <div class="avatar-wrapper" v-if="item.role!='system'">
          <!-- @ts-ignore -->
          <el-avatar :size="32" >{{item.role}}</el-avatar>
        </div>
      </template>

      <!-- 自定义头部 -->
      <template #header="{ item }" >
        <div class="header-wrapper" v-if="item.role!='system'">
          <div class="header-name" :class="item.role">
            {{ item.role === 'ai' ? 'AI' : '我' }}
          </div>
          <div>
            <Thinking
              v-if="item.think"
              auto-collapse
              :content="item.think"
              :status="item.thinking?'start':'end'"
            />
          </div>
        </div>
      </template>
      <!-- 自定义气泡内容 -->
      <template #content="{ item }">
        <div class="content-wrapper" :class="item.role">
          <div v-if="item.role==='user'">
            {{item.content}}
          </div>
          <template v-else-if="item.role==='ai'">
            <Typewriter :isMarkdown="true" :typing="true" :content="item.content"/>
          </template>
          <template v-else-if="item.role==='system'">
            <SystemPanel :chat="item"/>
          </template>
        </div>
      </template>

      <!-- 自定义底部 -->
      <template #footer="{ item }">
        <div class="footer-wrapper">
          <div class="footer-container">
            <div v-if="item.files">
              <div v-for="(url,index) in item.files" :key="index">
                <FilesCard :src="url" :name="url" />
              </div>
            </div>
          </div>
          <div class="footer-time" :class="item.role" v-if="item.atTime">
            {{ getNow(item.atTime) }}
          </div>
        </div>
      </template>

      <!-- 自定义 loading -->
      <template #loading>
        <div class="loading-container">
          <span>回</span>
          <span>复</span>
          <span>中</span>
          <span>。</span>
          <span>。</span>
          <span>。</span>
          <span>。</span>
          <span>。</span>
          <span>。</span>
          <span>。</span>
          <span>。</span>
        </div>
      </template>
    </BubbleList>
  </div>
</template>

<style scoped lang="scss">
.header-wrapper{
  width: var(--bubble-content-max-width);
  max-width: var(--bubble-content-max-width);
  .header-name.ai{
    text-align: right;
  }
}
.body-inner{
  max-width: 1000px;
  margin: 0 auto;
  overflow-x: hidden;
}
</style>
